package org.example.demo.lock;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.StampedLock;

public class LockExample7 {

    private static StampedLock lock = new StampedLock();

    private static List<String> data = new ArrayList<>();

    public static void write(){
        long stamped = -1;
        try {
            stamped = lock.writeLock();
            data.add("写线程写入的数据：" + stamped);
            System.out.println("写入的数据是："+stamped);
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlockWrite(stamped);
        }
    }

    public static void read(){
        long stamped = -1;
        try {
            stamped = lock.readLock();
            for (String s : data){
                System.out.println("读的数据是："+s);
            }
            TimeUnit.SECONDS.sleep(1);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }finally {
            lock.unlockRead(stamped);
        }
    }

    /**
     * 乐观读
     */
    public static void optimisticRead(){
        // 尝试拿一个乐观锁
        long stamped = lock.tryOptimisticRead();
        // 如果没有线程修改，再获取一个读锁
        if(lock.validate(stamped)){
            try {
                stamped = lock.readLock();
                for (String s : data){
                    System.out.println("读的数据是："+s);
                }
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }finally {
                lock.unlockRead(stamped);
            }

        }
    }

    public static void main(String[] args){
        ExecutorService executorService = Executors.newFixedThreadPool(10);
        Runnable readTask = ()->{
          for (int i =0;i<10;i++){
              read();
//              optimisticRead();
          }
        };
        Runnable writeTask = ()->{
            for (int i =0;i<10;i++){
                write();
            }
        };
        for (int i = 0; i < 9; i++) {
            executorService.submit(readTask);
        }
        executorService.submit(writeTask);
    }
}
